package ch.nostromo.tiffanys.engines.tiffanys.board;

import java.util.ArrayList;
import java.util.Random;

import ch.nostromo.lib.util.NosTools;
import ch.nostromo.tiffanys.engines.tiffanys.board.pieces.TiffanysBishop;
import ch.nostromo.tiffanys.engines.tiffanys.board.pieces.TiffanysKing;
import ch.nostromo.tiffanys.engines.tiffanys.board.pieces.TiffanysKnight;
import ch.nostromo.tiffanys.engines.tiffanys.board.pieces.TiffanysPawn;
import ch.nostromo.tiffanys.engines.tiffanys.board.pieces.TiffanysPiece;
import ch.nostromo.tiffanys.engines.tiffanys.board.pieces.TiffanysQueen;
import ch.nostromo.tiffanys.engines.tiffanys.board.pieces.TiffanysRook;
import ch.nostromo.tiffanys.game.board.Board;

public class TiffanysBoard {

  /**
   * The random numbers for the key computation.
   */
  private static long[][][] ZOBRIST_FACTORS;

  /**
   * The factor for black moves.
   */
  private static long ZOBRIST_SIDE_TO_MOVE;

  private static final int ZOBRIST_KING = 0;
  private static final int ZOBRIST_QUEEN = 1;
  private static final int ZOBRIST_ROOK = 2;
  private static final int ZOBRIST_KNIGHT = 3;
  private static final int ZOBRIST_BISHOP = 4;
  private static final int ZOBRIST_PAWN = 5;

  static {

    // Create a new multidimensional array.
    ZOBRIST_FACTORS = new long[2][6][64];

    Random rand = new Random();

    for (int i = 0; i < 64; i++) {
      for (int j = 0; j < 6; j++) {
        ZOBRIST_FACTORS[0][j][i] = rand.nextLong();
        ZOBRIST_FACTORS[1][j][i] = rand.nextLong();
      }
    }

    ZOBRIST_SIDE_TO_MOVE = rand.nextLong();
  }

  public static double stats_position_checK = 0;

  public static double stats_checked_check = 0;

  public static final int IDX_WHITE_KING = 121;

  public static final int IDX_BLACK_KING = 122;

  public static final int IDX_WHITE_MATERIAL = 123;

  public static final int IDX_BLACK_MATERIAL = 124;

  public static final int IDX_ZOBRIST_KEY = 125;

  public static final int IDX_WHITE_CASTELING = 126;

  public static final int IDX_BLACK_CASTELING = 127;

  public static final int[] BOARD64 = { 21, 22, 23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47, 48, 51, 52, 53, 54, 55, 56, 57, 58, 61, 62, 63, 64, 65, 66, 67, 68, 71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 83, 84,
      85, 86, 87, 88, 89, 92, 93, 94, 95, 96, 97, 98 };

  public static int[] BOARD121 = new int[121];

  static {
    for (int i = 0; i < 64; i++) {
      BOARD121[BOARD64[i]] = i;
    }
  }

  // Most important Board values
  private static long[] mainBoard = new long[128];

  public TiffanysBoard(Board board) {
    for (int i = 0; i < board.getBoardArray().length; i++) {
      mainBoard[i] = board.getBoardArray()[i];
    }
    setKingPositions(mainBoard);
    setMaterial(mainBoard);
    setZobristKey(mainBoard);
    mainBoard[IDX_WHITE_CASTELING] = 0;
    mainBoard[IDX_BLACK_CASTELING] = 0;
  }

  public long[] getBoard() {
    return mainBoard;
  }

  private void setMaterial(long[] board) {
    board[IDX_WHITE_MATERIAL] = 0;
    board[IDX_BLACK_MATERIAL] = 0;
    for (int i = 21; i <= 98; i++) {
      if (NosTools.checkMask(board[i], Board.PIECE_QUEEN)) {
        if (NosTools.checkMask(board[i], Board.OWNER_WHITE)) {
          board[IDX_WHITE_MATERIAL] += TiffanysQueen.MATERIAL_VALUE;
        } else {
          board[IDX_BLACK_MATERIAL] += TiffanysQueen.MATERIAL_VALUE;
        }
      }
      if (NosTools.checkMask(board[i], Board.PIECE_ROOK)) {
        if (NosTools.checkMask(board[i], Board.OWNER_WHITE)) {
          board[IDX_WHITE_MATERIAL] += TiffanysRook.MATERIAL_VALUE;
        } else {
          board[IDX_BLACK_MATERIAL] += TiffanysRook.MATERIAL_VALUE;
        }
      }
      if (NosTools.checkMask(board[i], Board.PIECE_KNIGHT)) {
        if (NosTools.checkMask(board[i], Board.OWNER_WHITE)) {
          board[IDX_WHITE_MATERIAL] += TiffanysKnight.MATERIAL_VALUE;
        } else {
          board[IDX_BLACK_MATERIAL] += TiffanysKnight.MATERIAL_VALUE;
        }
      }
      if (NosTools.checkMask(board[i], Board.PIECE_BISHOP)) {
        if (NosTools.checkMask(board[i], Board.OWNER_WHITE)) {
          board[IDX_WHITE_MATERIAL] += TiffanysBishop.MATERIAL_VALUE;
        } else {
          board[IDX_BLACK_MATERIAL] += TiffanysBishop.MATERIAL_VALUE;
        }
      }
      if (NosTools.checkMask(board[i], Board.PIECE_PAWN)) {
        if (NosTools.checkMask(board[i], Board.OWNER_WHITE)) {
          board[IDX_WHITE_MATERIAL] += TiffanysPawn.MATERIAL_VALUE;
        } else {
          board[IDX_BLACK_MATERIAL] += TiffanysPawn.MATERIAL_VALUE;
        }
      }
    }
  }

  private void setKingPositions(long[] board) {
    for (int i = 21; i <= 98; i++) {
      if (NosTools.checkMask(board[i], Board.PIECE_KING)) {
        if (NosTools.checkMask(board[i], Board.OWNER_WHITE)) {
          board[IDX_WHITE_KING] = i;
        } else {
          board[IDX_BLACK_KING] = i;
        }
      }
    }
  }

  private void setZobristKey(long[] board) {
    long val = 0L;

    for (int i = 0; i < TiffanysBoard.BOARD64.length; i++) {
      if ((Board.EMPTY_FIELD & board[TiffanysBoard.BOARD64[i]]) == 0) {
        // Get the typ
        // 0 = KING
        int type = ZOBRIST_KING;
        if ((Board.PIECE_PAWN & board[TiffanysBoard.BOARD64[i]]) != 0) {
          type = ZOBRIST_PAWN;
        } else if ((Board.PIECE_KNIGHT & board[TiffanysBoard.BOARD64[i]]) != 0) {
          type = ZOBRIST_KNIGHT;
        } else if ((Board.PIECE_BISHOP & board[TiffanysBoard.BOARD64[i]]) != 0) {
          type = ZOBRIST_BISHOP;
        } else if ((Board.PIECE_ROOK & board[TiffanysBoard.BOARD64[i]]) != 0) {
          type = ZOBRIST_ROOK;
        } else if ((Board.PIECE_QUEEN & board[TiffanysBoard.BOARD64[i]]) != 0) {
          type = ZOBRIST_QUEEN;
        }

        // get the color
        int col = 0;
        if ((Board.OWNER_BLACK & board[TiffanysBoard.BOARD64[i]]) != 0) {
          col = 1;
        }

        val ^= ZOBRIST_FACTORS[col][type][i];

        board[IDX_ZOBRIST_KEY] = val;

      }
    }

    // if (false) {
    // val ^= _blackMoves;
    // }

  }

  private static int getZobristType(int boardPiece) {
    if (boardPiece == Board.PIECE_KING) {
      return ZOBRIST_KING;
    } else if (boardPiece == Board.PIECE_BISHOP) {
      return ZOBRIST_BISHOP;
    } else if (boardPiece == Board.PIECE_KNIGHT) {
      return ZOBRIST_KNIGHT;
    } else if (boardPiece == Board.PIECE_ROOK) {
      return ZOBRIST_ROOK;
    } else if (boardPiece == Board.PIECE_QUEEN) {
      return ZOBRIST_QUEEN;
    } else {
      return ZOBRIST_PAWN;
    }
  }

  // ------------------------- STATIC Board functions -------------------------

  public static final int invertColor(int color) {
    if (color == Board.OWNER_WHITE) {
      return Board.OWNER_BLACK;
    } else {
      return Board.OWNER_WHITE;
    }
  }

  public static final int getOwner(long field) {
    if (NosTools.checkMask(field, Board.OWNER_WHITE))
      return Board.OWNER_WHITE;
    if (NosTools.checkMask(field, Board.OWNER_BLACK))
      return Board.OWNER_BLACK;
    return Board.EMPTY_FIELD;
  }

  public static final boolean isEnemyPiece(long field, int myColor) {
    return (getOwner(field) == invertColor(myColor));
  }

  public static final boolean isEmptyField(long field) {
    return NosTools.checkMask(field, Board.EMPTY_FIELD);
  }

  public static final boolean isMovedField(long field) {
    return NosTools.checkMask(field, Board.MOVED);
  }

  public static final boolean isValidMoveToField(long field, int myColor) {
    return (isEmptyField(field) || isEnemyPiece(field, myColor));
  }

  public static final boolean isValidHitMoveToField(long field, int myColor) {
    return (isEnemyPiece(field, myColor));
  }

  public static boolean[] getValidMoveFields(long board[], int enemyColor) {
    boolean[] result = new boolean[120];
    for (int i = 21; i <= 98; i++) {
      if ((Board.EMPTY_FIELD & board[i]) != 0 || (enemyColor & board[i]) != 0) {
        result[i] = true;
      }
    }
    return result;
  }

  public static int[] getEnemyPiecesValues(long board[], int enemyColor) {
    int[] result = new int[120];
    for (int i = 21; i <= 98; i++) {
      if ((enemyColor & board[i]) != 0) {
        if ((Board.PIECE_PAWN & board[i]) != 0) {
          result[i] = 10000 + TiffanysPawn.MATERIAL_VALUE;
        } else if ((Board.PIECE_KNIGHT & board[i]) != 0) {
          result[i] = 10000 + TiffanysKnight.MATERIAL_VALUE;
        } else if ((Board.PIECE_ROOK & board[i]) != 0) {
          result[i] = 10000 + TiffanysRook.MATERIAL_VALUE;
        } else if ((Board.PIECE_QUEEN & board[i]) != 0) {
          result[i] = 10000 + TiffanysQueen.MATERIAL_VALUE;
        } else {
          result[i] = 10000 + TiffanysKing.MATERIAL_VALUE;
        }
      }
    }
    return result;

  }

  public static final TiffanysMove[] generateHitMoveList(TiffanysMove[] moves, long[] board, int color) {
    for (int i = 0; i < moves.length; i++) {
      moves[i].isSet = false;
    }

    int enemyColor = invertColor(color);
    int[] enemyValues = getEnemyPiecesValues(board, enemyColor);
    boolean[] validMoveFields = getValidMoveFields(board, enemyColor);

    int movesIdx = 0;
    for (int i = 21; i <= 98; i++) {
      if ((color & board[i]) != 0) {
        if ((Board.PIECE_KNIGHT & board[i]) != 0) {
          movesIdx = TiffanysKnight.getHitMoveList(i, movesIdx, moves, enemyValues);
        } else if ((Board.PIECE_PAWN & board[i]) != 0) {
          movesIdx = TiffanysPawn.getHitMoveList(board, i, color, movesIdx, moves, enemyValues);
        } else if ((Board.PIECE_KING & board[i]) != 0) {
          movesIdx = TiffanysKing.getHitMoveList(i, movesIdx, moves, enemyValues);
        } else if ((Board.PIECE_BISHOP & board[i]) != 0) {
          movesIdx = TiffanysBishop.getHitMoveList(i, movesIdx, moves, enemyValues, validMoveFields);
        } else if ((Board.PIECE_QUEEN & board[i]) != 0) {
          movesIdx = TiffanysQueen.getHitMoveList(i, movesIdx, moves, enemyValues, validMoveFields);
        } else if ((Board.PIECE_ROOK & board[i]) != 0) {
          movesIdx = TiffanysRook.getHitMoveList(i, movesIdx, moves, enemyValues, validMoveFields);
        }
      }
    }
    return moves;
  }

  public static final void generateMoveList(TiffanysMove[] moves, long[] board, int color) {
    for (int i = 0; i < moves.length; i++) {
      moves[i].isSet = false;
    }

    int enemyColor = invertColor(color);
    int[] enemyValues = getEnemyPiecesValues(board, enemyColor);
    boolean[] validMoveFields = getValidMoveFields(board, enemyColor);

    int movesIdx = 0;
    for (int i = 21; i <= 98; i++) {
      if ((color & board[i]) != 0) {
        if ((Board.PIECE_KNIGHT & board[i]) != 0) {
          movesIdx = TiffanysKnight.getMoveList(i, movesIdx, moves, enemyValues, validMoveFields);
        } else if ((Board.PIECE_PAWN & board[i]) != 0) {
          movesIdx = TiffanysPawn.getMoveList(board, i, color, movesIdx, moves, enemyValues);
        } else if ((Board.PIECE_KING & board[i]) != 0) {
          movesIdx = TiffanysKing.getMoveList(board, i, color, movesIdx, moves, enemyValues, validMoveFields);
        } else if ((Board.PIECE_BISHOP & board[i]) != 0) {
          movesIdx = TiffanysBishop.getMoveList(i, movesIdx, moves, enemyValues, validMoveFields);
        } else if ((Board.PIECE_QUEEN & board[i]) != 0) {
          movesIdx = TiffanysQueen.getMoveList(i, movesIdx, moves, enemyValues, validMoveFields);
        } else if ((Board.PIECE_ROOK & board[i]) != 0) {
          movesIdx = TiffanysRook.getMoveList(i, movesIdx, moves, enemyValues, validMoveFields);
        }
      }
    }

  }

  public static TiffanysMove[] generateLegalMovesList(long[] board, int color) {
    ArrayList<TiffanysMove> result = new ArrayList<TiffanysMove>();

    TiffanysMove[] moves = new TiffanysMove[100];
    for (int i = 0; i < moves.length; i++) {
      moves[i] = new TiffanysMove();
    }

    generateMoveList(moves, board, color);

    for (int i = 0; i < moves.length; i++) {
      if (moves[i].isSet) {
        TiffanysBoard.makeMove(board, moves[i], color);
        boolean isCheck = checkForCheck(board, color);
        TiffanysBoard.takeBackMove(board, moves[i]);
        if (!isCheck) {
          result.add(moves[i]);
        }
      }
    }

    return result.toArray(new TiffanysMove[result.size()]);
  }

  public static void takeBackMove(long[] board, TiffanysMove move) {
    board[IDX_ZOBRIST_KEY] = move.backupZobrist;

    board[move.from] = move.backupFrom;
    board[move.to] = move.backupTo;
    board[IDX_BLACK_KING] = move.backupBlackKing;
    board[IDX_BLACK_MATERIAL] = move.backupBlackMaterial;
    board[IDX_WHITE_KING] = move.backupWhiteKing;
    board[IDX_WHITE_MATERIAL] = move.backupWhiteMaterial;

    board[Board.IDX_ENPASSANT_FIELD] = move.backupEpField;
    if (move.enPassantMove) {
      board[move.enPassantOpponentTake] = move.backupEpTakenField;
    }

    // Backup castling fields
    if (move.castling == TiffanysMove.CASTLING_LONG) {
      board[move.castlingRook] = move.backupCastlingRook;
      board[move.castlingRook + 3] = move.backupCastlingRookTo;
      board[IDX_WHITE_CASTELING] = move.backupCastelingWhite;
      board[IDX_BLACK_CASTELING] = move.backupCastelingBlack;
    } else if (move.castling == TiffanysMove.CASTLING_SHORT) {
      board[move.castlingRook] = move.backupCastlingRook;
      board[move.castlingRook - 2] = move.backupCastlingRookTo;
      board[IDX_WHITE_CASTELING] = move.backupCastelingWhite;
      board[IDX_BLACK_CASTELING] = move.backupCastelingBlack;
    }

  }

  public static boolean checkForCheck(long[] board, int currentColor) {
    stats_checked_check++;
    if (currentColor == Board.OWNER_WHITE) {
      return TiffanysPiece.isKingAttacked(board, board[IDX_WHITE_KING], currentColor);
    } else {
      return TiffanysPiece.isKingAttacked(board, board[IDX_BLACK_KING], currentColor);
    }
  }

  public static void makeMove(long[] board, TiffanysMove move, int color) {

    move.backupZobrist = board[IDX_ZOBRIST_KEY];

    int zobrCol = 0;
    if (color == Board.OWNER_BLACK) {
      zobrCol = 1;
    }

    int zobrFrom = 0;
    int zobrTo = 0;
    int zobrType = 0;

    // Now backup the board fields for later take back of the move
    move.backupFrom = board[move.from];
    move.backupTo = board[move.to];
    move.backupBlackKing = board[IDX_BLACK_KING];
    move.backupWhiteKing = board[IDX_WHITE_KING];
    move.backupWhiteMaterial = board[IDX_WHITE_MATERIAL];
    move.backupBlackMaterial = board[IDX_BLACK_MATERIAL];
    move.backupEpField = board[Board.IDX_ENPASSANT_FIELD];

    if (move.enPassantMove) {
      move.backupEpTakenField = board[move.enPassantOpponentTake];
    }

    // Backup castling fields
    if (move.castling == TiffanysMove.CASTLING_LONG) {
      move.backupCastlingRook = board[move.castlingRook];
      move.backupCastlingRookTo = board[move.castlingRook + 3];
    } else if (move.castling == TiffanysMove.CASTLING_SHORT) {
      move.backupCastlingRook = board[move.castlingRook];
      move.backupCastlingRookTo = board[move.castlingRook - 2];
    }

    int enemyColor = invertColor(color);
    int enemyMaterialIdx = IDX_WHITE_MATERIAL;
    int ownMaterialIdx = IDX_BLACK_MATERIAL;
    if (enemyColor == Board.OWNER_BLACK) {
      enemyMaterialIdx = IDX_BLACK_MATERIAL;
      ownMaterialIdx = IDX_WHITE_MATERIAL;
    }

    // Castling first
    if (move.castling != TiffanysMove.CASTLING_NO) {

      move.backupCastelingWhite = board[IDX_WHITE_CASTELING];
      move.backupCastelingBlack = board[IDX_BLACK_CASTELING];

      if (color == Board.OWNER_WHITE) {
        board[IDX_WHITE_KING] = move.to;
        board[IDX_WHITE_CASTELING] = 1;
      } else if (color == Board.OWNER_BLACK) {
        board[IDX_BLACK_KING] = move.to;
        board[IDX_BLACK_CASTELING] = 1;
      }

      board[move.to] = Board.BOARD_LEGAL + color + Board.PIECE_KING + Board.MOVED;
      board[move.from] = Board.BOARD_LEGAL + Board.EMPTY_FIELD;

      // ZOBRIST FROM -> TO
      zobrFrom = BOARD121[move.from];
      zobrTo = BOARD121[move.to];
      zobrType = ZOBRIST_KING;
      board[IDX_ZOBRIST_KEY] ^= ZOBRIST_FACTORS[zobrCol][zobrType][zobrFrom];
      board[IDX_ZOBRIST_KEY] ^= ZOBRIST_FACTORS[zobrCol][zobrType][zobrTo];

      if (move.castling == TiffanysMove.CASTLING_LONG) {
        board[move.castlingRook + 3] = board[move.castlingRook];
        board[move.castlingRook] = Board.BOARD_LEGAL + Board.EMPTY_FIELD;

        // ZOBRIST FROM -> TO
        zobrFrom = BOARD121[move.castlingRook];
        zobrTo = BOARD121[move.castlingRook + 3];
        zobrType = ZOBRIST_ROOK;
        board[IDX_ZOBRIST_KEY] ^= ZOBRIST_FACTORS[zobrCol][zobrType][zobrFrom];
        board[IDX_ZOBRIST_KEY] ^= ZOBRIST_FACTORS[zobrCol][zobrType][zobrTo];

      } else {
        board[move.castlingRook - 2] = board[move.castlingRook];
        board[move.castlingRook] = Board.BOARD_LEGAL + Board.EMPTY_FIELD;

        // ZOBRIST FROM -> TO
        zobrFrom = BOARD121[move.castlingRook];
        zobrTo = BOARD121[move.castlingRook - 2];
        zobrType = ZOBRIST_ROOK;
        board[IDX_ZOBRIST_KEY] ^= ZOBRIST_FACTORS[zobrCol][zobrType][zobrFrom];
        board[IDX_ZOBRIST_KEY] ^= ZOBRIST_FACTORS[zobrCol][zobrType][zobrTo];

      }

    } else {

      // Calculate new material if enemy takes a hit
      if (NosTools.checkMask(board[move.to], enemyColor)) {
        if (NosTools.checkMask(board[move.to], Board.PIECE_QUEEN)) {
          board[enemyMaterialIdx] -= TiffanysQueen.MATERIAL_VALUE;
        } else if (NosTools.checkMask(board[move.to], Board.PIECE_ROOK)) {
          board[enemyMaterialIdx] -= TiffanysRook.MATERIAL_VALUE;
        } else if (NosTools.checkMask(board[move.to], Board.PIECE_BISHOP)) {
          board[enemyMaterialIdx] -= TiffanysBishop.MATERIAL_VALUE;
        } else if (NosTools.checkMask(board[move.to], Board.PIECE_KNIGHT)) {
          board[enemyMaterialIdx] -= TiffanysKnight.MATERIAL_VALUE;
        } else if (NosTools.checkMask(board[move.to], Board.PIECE_PAWN)) {
          board[enemyMaterialIdx] -= TiffanysPawn.MATERIAL_VALUE;
        }
        move.hitmove = true;
      }

      // Calculate new material if promotion
      if (move.startingPiece != move.endingPiece) {
        if (move.endingPiece == Board.PIECE_BISHOP) {
          board[ownMaterialIdx] += TiffanysBishop.MATERIAL_VALUE;
          board[ownMaterialIdx] -= TiffanysPawn.MATERIAL_VALUE;
        }
        if (move.endingPiece == Board.PIECE_ROOK) {
          board[ownMaterialIdx] += TiffanysRook.MATERIAL_VALUE;
          board[ownMaterialIdx] -= TiffanysPawn.MATERIAL_VALUE;
        }
        if (move.endingPiece == Board.PIECE_KNIGHT) {
          board[ownMaterialIdx] += TiffanysKnight.MATERIAL_VALUE;
          board[ownMaterialIdx] -= TiffanysPawn.MATERIAL_VALUE;
        }
        if (move.endingPiece == Board.PIECE_QUEEN) {
          board[ownMaterialIdx] += TiffanysQueen.MATERIAL_VALUE;
          board[ownMaterialIdx] -= TiffanysPawn.MATERIAL_VALUE;
        }

      }

      // If king is moved, save his position
      if (move.startingPiece == Board.PIECE_KING && color == Board.OWNER_WHITE) {
        board[IDX_WHITE_KING] = move.to;
      } else if (move.startingPiece == Board.PIECE_KING && color == Board.OWNER_BLACK) {
        board[IDX_BLACK_KING] = move.to;
      }

      // Remove piece
      board[move.from] = Board.BOARD_LEGAL + Board.EMPTY_FIELD;

      // ZOBRIST
      zobrFrom = BOARD121[move.from];
      zobrType = getZobristType(move.startingPiece);
      board[IDX_ZOBRIST_KEY] ^= ZOBRIST_FACTORS[zobrCol][zobrType][zobrFrom];

      // Move piece
      if (move.startingPiece == move.endingPiece) {
        board[move.to] = Board.BOARD_LEGAL + color + move.startingPiece + Board.MOVED;

        zobrTo = BOARD121[move.to];
        board[IDX_ZOBRIST_KEY] ^= ZOBRIST_FACTORS[zobrCol][zobrType][zobrTo];

      } else {
        board[move.to] = Board.BOARD_LEGAL + color + move.endingPiece + Board.MOVED;

        zobrType = getZobristType(move.endingPiece);
        zobrTo = BOARD121[move.to];
        board[IDX_ZOBRIST_KEY] ^= ZOBRIST_FACTORS[zobrCol][zobrType][zobrTo];
      }

      // Remove en passant pawn if needed
      if (move.enPassantMove) {
        if (color == Board.OWNER_WHITE) {
          board[move.to - 10] = Board.BOARD_LEGAL + Board.EMPTY_FIELD;
        } else {
          board[move.to + 10] = Board.BOARD_LEGAL + Board.EMPTY_FIELD;
        }
        move.hitmove = true;
      }

      // Set or remove enPassant field
      if (move.leavingEnPassantField > 0) {
        board[Board.IDX_ENPASSANT_FIELD] = move.leavingEnPassantField;
      } else {
        board[Board.IDX_ENPASSANT_FIELD] = -1;
      }

      board[IDX_ZOBRIST_KEY] ^= ZOBRIST_SIDE_TO_MOVE;

    }
  }
}
